package JavaN.Java8;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
class User {
    private Integer id;
    private String  username;
    private int     age;
}

/**
 * ●Java8中有两大最为重要的改变。
 * 第一个是Lambda表达式;另外一个则是Stream API。
 * ●Stream API (java.util.stream)把真正的函数式编程风格引入到Java中。这
 * 是目前为止对Java类库最好的补充，因为Stream API可以极大提供Java程
 * 序员的生产力，让程序员写出高效率、干净、简洁的代码。
 * ●Stream是Java8中处理集合的关键抽象概念，它可以指定你希望对集合进
 * 行的操作，可以执行非常复杂的查找、过滤和映射数据等操作。使用
 * ●Stream API对集合数据进行操作，就类似于使用SQL执行的数据库查询。
 * 也可以使用Stream API来并行执行操作。简言之，StreamAPl 提供了- -种
 * 高效且易于使用的处理数据的方式。
 *
 * ●1- 创建Stream
 *  一个数据源(如:集合、数组)，获取一个流
 * ●2- 中间操作
 *  一个中间操作链，对数据源的数据进行处理
 * ●3- 终止操作(终端操作)
 *  一旦执行终止操作，就执行中间操作链，并产生结果。之后，不会再被使用
 */

/**
 * 1. Stream关注的是对数据的运算，与CPU打交道
 *    集合关注的是数据的存储，与内存打交道
 * 2.①Stream 自己不会存储元素。
 *   ②Stream 不会改变源对象。相反，他们会返回一个持有结果的新Stream。
 *   ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
 *
 * 3.Stream 执行流程
 *   ① Stream的实例化
 *   ② 一系列的中间操作（过滤、映射、...)
 *   ③ 终止操作
 * 4.说明：
 *   4.1 一个中间操作链，对数据源的数据进行处理
 *   4.2 一旦执行终止操作，就执行中间操作链，并产生结果。之后，不会再被使用
 *  测试Stream的实例化
 *
 */


public class StreamAPI {
    public static void main(String[] args) {
        Stream的部分方法1();
    }

    private static void Stream转集合() {
        int[] arr = new int[]{1,2,3,4,5,6,7,8,9};
        List<User> list = List数组();
        List<User> collect = list.stream().filter(e -> e.getAge() > 20).collect(Collectors.toList());
        //Stream<User>  把这种类型转换成Collectors.toList()指定的类型
        collect.forEach(System.out::println);
    }

    private static void Stream求和() {
        int[] arr = new int[]{1,2,3,4,5,6,7,8,9};
        System.out.println(Arrays.stream(arr).reduce(0/*初始值没有的话结果OptionalInt[45]*/,Integer::sum));//45
        System.out.println(List数组().stream().map(User::getAge).reduce(Integer::sum));//Optional[273]
    }

    private static void Stream的匹配与查找方法() {
        List<User> list=List数组();
        System.out.println("allMatch(Predicate p)——检查是否匹配所有元素。  boolean类型");
        System.out.println(list.stream().allMatch(e -> e.getAge() > 18));//false 是否全部  age>18
        System.out.println("anyMatch(Predicate p)——检查是否至少匹配一个元素。 boolean类型");
        System.out.println(list.stream().anyMatch(e -> e.getAge() > 18));//true 是否有   age>18
        System.out.println("noneMatch(Predicate p)——检查是否'没有'匹配的元素。boolean类型");
        System.out.println(list.stream().anyMatch(e -> e.getAge() > 66));//false
        System.out.println("findFirst******返回第一个元素");
        Optional<User> first = list.stream().findFirst();//Optional避免空指针造出的类
        System.out.println(first);
        System.out.println("findAny——返回当前流中的任意元素  随机的");
        Optional<User> any = list.stream().findAny();//串行流  总是第一个
        Optional<User> any1 = list.parallelStream().findAny();//并行流  总是某一个(第六个)
//        final Stream<User> stream = any1.stream();//JDK9新特性  可以将Optional-》Stream
        System.out.println("串行流 总是第一个"+any);
        System.out.println("并行流 总是某一个(第六个)"+any1);
//        System.out.println("*****parallelStream*并行流***自带多线程**用线程池**哪个线程抢到哪个运算*****");
//        list.parallelStream().forEach(num->System.out.println(Thread.currentThread().getName()+">>"+num));
        System.out.println("count——返回流中元素的总个数  是个long类型");
        System.out.println(list.stream().count());
        System.out.println("max(Comparator c)——返回流中最大值");
        System.out.println(list.stream().max((e, f)-> Integer.compare(e.getAge(), f.getAge())));
        //Optional[User(id=1005, username=李彦宏, age=65)]
        System.out.println("min(Comparator c)——返回流中最小值同上");
        System.out.println(list.stream().map(e->e.getAge()).min(Integer::compareTo));//Optional[12]
        System.out.println(" forEach(Consumer c)——内部迭代");
        list.stream().forEach(System.out::print);
    }

    private static void Stream的map和flatMap的区别() {
        System.out.println("****map*和*flatMap****区别********* ");
        List<String> list = Arrays.asList("aa","bb","cc","dd");
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPI::StringToCharArray);//正常执行
        streamStream.forEach(s->s.forEach(System.out::print));//看返回值就知道

        System.out.println();
        Stream<Character> characterStream = list.stream().flatMap(StreamAPI::StringToCharArray);//执行后 数组会自动拆分
        characterStream.forEach(System.out::print);//直接可以输出
    }

    private static Stream<Character> StringToCharArray(String str) {
        List<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

    private static void Stream的部分方法1() {
        List<User> list=List数组();
        list.stream()/*创建一个顺序流*/.filter(t->t.getId()%2==0)//filter过滤
                .filter(t->t.getAge()>24)
                .map(x-> x.getUsername().toUpperCase())//转大写
                .sorted(String::compareTo)//(o1, o2) ->  o2.compareTo(o1)//排序
                .limit(1)//使元素不得超过给定的数量
                .forEach(System.out::println);

        System.out.println("****skip()**跳过多少元素**************************");
        list.stream().skip(7).forEach(System.out::println);//当数字大于数组长度   没有输出
        System.out.println("****distinct()**去重***用equals和hashCode********");
        list.stream().distinct().forEach(System.out::println);//只有完全相同才会一致d

//        map(Function f)——接收一个函数作为参数，将元素转换成其他形式或提取信息，该函数会被应用到每个元素上，并将其映射成一个新的元素。
        System.out.println("****map()**去重***用equals和hashCode**********");
        List<Integer> list1=Arrays.asList(1,2,3);
        list1.stream().map(x-> x*2)//把每个元素变成原来的2倍
                .toArray();//转换成数组//collect(Collectors.toList());//把这个流转成List集合
//        count()//返回元素数量
    }

    private static List<User> List数组() {
        List<User> list= new ArrayList<>();
        list.add(new User(1001, "马化腾", 34));
        list.add(new User(1002, "马云", 12));
        list.add(new User(1003, "刘强东", 33));
        list.add(new User(1004, "雷军", 26));
        list.add(new User(1005, "李彦宏", 65));
        list.add(new User(1006, "比尔盖茨", 42));
        list.add(new User(1007, "任正非", 26));
        list.add(new User(1008, "扎克伯格", 35));
        return list;
    }

    private static void Stream的创建() {

        User u1=new User(16,"a",23);
        User u2=new User(17,"b",24);
        User u3=new User(19,"c",22);
        User u4=new User(15,"d",28);
        User u5=new User(17,"e",26);

        List<User> list= Arrays.asList(u1,u2,u3,u4,u5);

        Stream<User> stream1 = list.stream();//创建一个顺序流
        Stream<User> Stream2 = list.parallelStream();//创建一个并行流

        int[] arr = new int[]{1,2,3,4,5,6,7,8,9};
        IntStream stream3 = Arrays.stream(arr);

        Stream<Integer> Stream4 = Stream.of(1, 2, 3, 4, 5, 6);

        //iterate迭代                     每次加2   遍历前十个       循环输出
        Stream.iterate(0/*起始值*/,t -> t+2).limit(10).forEach(System.out::println);

             //  生成
        Stream.generate(Math::random).limit(10).forEach(System.out::println);//生成


    }  //流式接口
}